#ifndef RING_BUFFER_H
#define RING_BUFFER_H

#include <atomic>
#include <iostream>
#include <memory>
#include <vector>

namespace MSF {

template <typename T>
class RingBuffer {
 public:
  RingBuffer(unsigned capacity = 60)
      : _buffer(capacity), _capacity(capacity), _numDatas(0) {}

  ~RingBuffer() {}

  bool push(const T& data) { return pushData(std::forward<T>(data)); }
  bool push(T&& data) { return pushData(data); }

  bool pop(T& data) {
    if (_numDatas > 0) {
      data = std::move(_buffer[_getPos]);
      add(_getPos);
      _numDatas--;
      return true;
    }
    return false;
  }

  bool isFull() const { return ((_numDatas == _capacity) ? true : false); }
  bool isEmpty() const { return ((_numDatas == 0) ? true : false); }
  int size() const { return _numDatas; }

 private:
  template <typename F>
  bool pushData(F&& data) {
    if (_numDatas < _capacity) {
      _buffer[_putPos] = std::forward<F>(data);
      add(_putPos);
      _numDatas++;
      return true;
    }

    return false;
  }

  void add(int& pos) { pos = (((pos + 1) == _capacity) ? 0 : (pos + 1)); }

  int _capacity = 0;
  int _putPos = 0;
  int _getPos = 0;

  std::atomic_int _numDatas;
  std::vector<T> _buffer;
};

}  // namespace MSF
